Conversation
Signed-off-by: Eli Bosley <eli@bosley.dev>
Signed-off-by: Eli Bosley <eli@bosley.dev>
|
Thank you! I apologize for missing the earlier comments on my PR. |
|
@elibosley You're the author in the commits, so it's just a carry-over. I'll handle the rest! Thank you for your contribution! |
|
Thanks for the contribution. We will review this PR soon. |
|
@henry118 Just a cordial reminder. I just would like this before v1.20.1 to blend with the other PRs. |
Signed-off-by: Seungmin Kim <8457324+ehfd@users.noreply.github.com>
|
@henry118 I reduced the code footprint dramatically while doing the same work. FYI. |
henry118
left a comment
There was a problem hiding this comment.
@ehfd Thanks for bearing with me. A few thoughts on the general approach:
- I still think we want a flag here to gate this feature. Unconditionally discovering and mounting the full 32-bit lib set for every container is probably unnecessary for most use cases;
- IMO we can skip the 32-bit injection for alpine entirely. This feels like solving for a use case we would never support (32-bit containers), and the host is always assumed 64-bit.
|
I found that i386 multiarch is not a supported concept in musl; understood. |
Signed-off-by: Seungmin Kim <8457324+ehfd@users.noreply.github.com>
|
I made a compromise where, host-wise, 32-bit libraries are on by default in CDI specs when available, explicitly disabled by Otherwise, the condition to provision inside the container is when:
|
|
Associated to #2049 ? |
Superseding and takeover of #1968.
Closes #1968
Reviewer: @henry118 @cdesiniotis
Continues #1968 by @elibosley, whose two commits are included here unmodified. The commits that follow address the review on this PR. Related to #563.
Background
ldcache.List()returns the 32-bit and 64-bit library sets separately, and the CDI lookup path discarded the 32-bit one. The default library locator also stopped at the first source that produced a match, so the linker cache could not contribute libraries from a compat32 directory once a library had been found in a predefined native path.On a multilib host the generated spec therefore exposes the 64-bit driver stack while leaving a 32-bit application — a Steam or Proton title, a 32-bit CUDA or VDPAU consumer — without the matching vendor libraries, even though ELF32 driver libraries are installed and catalogued in the host's linker cache. Such applications fall back to software rendering or fail to start.
Where the gate is
The review asked for a flag to gate this, and for the 32-bit stack to be kept out of Alpine entirely. The gate is now in two parts, and the part that decides whether a container is affected is the container's own:
update-ldcachehook decides this per container, at a point where both the ELF class of every injected library and the container's own userspace are directly observable.Discovery, on the host
The 32-bit set from
ldcache.List()is no longer discarded, and the default library locator merges the unique matches of its sources instead of stopping at the first one that produces a match, so the linker cache can contribute a compat32 directory even when a predefined native path already matched. The native results keep their position at the front.This is on by default rather than opt-in because:
.runinstaller asks whether to install the 32-bit compatibility libraries, and Debian and Ubuntu ship them as a separate:i386package. A host without them produces the same spec as today.To leave them out of the spec entirely:
$ nvidia-ctk cdi generate --disable-compat32and
nvcdi.WithFeatureFlags(nvcdi.FeatureDisableCompat32Libraries)for API consumers such as the device plugin.Exposure, in the container
internal/ldconfigclassifies each injected directory by the ELF class of the libraries it contains (debug/elf) and adds a 32-bit directory to the container's search path only when:compat32/alldriver capability throughNVIDIA_DRIVER_CAPABILITIES— the capability that drives--compat32innvidia-container-cli— or it ships a dynamic linker for 32-bit applications (/lib/ld-linux.so.2or/lib32/ld-linux.so.2;/lib/ld-linux-armhf.so.3or/lib/ld-linux.so.3on arm64).Otherwise the 32-bit directories are left out of the
00-nvcr-*.confdrop-in and of the musl.pathfile, and the dynamic linker never searches them. A stockubuntu:24.04oralpinecontainer is therefore unaffected, and a multilib image — the one that has a reason to care — works with nothing set.Notes on this:
--userns=nomap, nvidia-cdi-hook fails when running a container with --userns nomap #648); a container whose capabilities cannot be determined is treated as not having requested them, and the linker check decides.i386-linux-gnuorlib32, so it also holds for hosts that do not follow those conventions.musl
/etc/ld-musl-<arch>.pathcarries no architecture information: musl's dynamic linker loads the first file matching the requested name and fails instead of continuing the search, so a wrong-arch match breaks the workload. There is no second.pathfile to route the 32-bit directories to, so they are never written to one. The hook additionally:00-nvcr-*.confdrop-in;/lib:/usr/local/lib:/usr/libsearch path when it creates the file. Alpine ships no.pathfile, so the hook creates one, and creating it replaces the default search path./usr/local/libis silently dropped today; this is a pre-existing bug in the same function;isMuslnow also detects the musl dynamic linker, falling back to the/etc/alpine-releasecheck it used before.Verification
Bare-metal x86_64, Ubuntu 26.04, 2x Tesla P100-SXM2-16GB, driver 580.178.04,
libnvidia-gl-580:i386installed, Docker 29.7.2. Specs generated withnvidia-ctk cdi generate --mode=nvmlinto/etc/cdiunder distinct vendors and requested withdocker run --runtime=runc --device <vendor>/gpu=all.Discovery. The generated spec grows from 58 to 83
hostPathentries: 25 ELF32 driver libraries under/usr/lib/i386-linux-gnu, their soname symlinks, and--folder /usr/lib/i386-linux-gnu{,/vdpau}for theupdate-ldcachehook.The musl failure that motivates the container-side gate. With the 32-bit libraries in the spec and a hook that adds every injected directory to the
.pathfile, in an Alpine container whose image ships one:With this PR, same image and spec:
/etc/ld-musl-x86_64.pathholds the native driver directories and no 32-bit entry. In the image above, which ships a.pathfile, the native driver directories are prepended and the existing entries keep their order.32-bit workloads. In multilib images (
ubuntu:26.04anddebian:trixiewithlibc6:i386,libvulkan1{,:i386},libegl1{,:i386},libx11-6{,:i386}andlibxext6{,:i386}), a 32-bit process enumerates both P100s through Vulkan (vkCreateInstance,vkEnumeratePhysicalDevices,vkGetPhysicalDeviceProperties, served by the injected 32-bitlibGLX_nvidia.so.0ICD) and initialises the CUDA driver API (cuInitsucceeds and reports both devices through the 32-bitlibcuda.so.1). Onmainthe same programs fail withVK_ERROR_INCOMPATIBLE_DRIVERand a faileddlopen, while their 64-bit builds pass either way. These images carrylibc6:i386, so the hook exposes the 32-bit directories to them with nothing set. The ICDdlopens glvnd'slibEGL.so.1and the X11 client libraries of its own architecture, so the image has to provide those; without them it fails identically onmain.Second host, discovery and the gating decision. x86_64, Tesla V100-SXM2-32GB, driver 580.173.02,
libnvidia-gl-580:i386installed.nvidia-ctk cdi generate --mode=nvmlproduces 83 mounts wheremainproduces 58, the 25 additional entries being the ELF32 driver libraries under/usr/lib/i386-linux-gnu{,/vdpau}, which are also passed to theupdate-ldcachehook as--folderarguments;--disable-compat32produces a spec identical to the one generated onmain. The hook's decision, run against real filesystems rather than fixtures: that host's own root, which carries/lib/ld-linux.so.2, is allowed with nothing set; an unpackedalpine-minirootfs-3.21.3is skipped, with and without thecompat32capability; and the ELF class filter over the four driver directories keeps/usr/lib/x86_64-linux-gnu{,/vdpau}and drops/usr/lib/i386-linux-gnu{,/vdpau}.Unit tests cover the locator merge and the ldcache split (from #1968), the discovery opt-out, the ELF class filter, the container-side gate in all of its cases, the
.pathfile ordering and default-search-path preservation, musl detection, and the container environment lookup the capability is read from. Tests for the touched packages pass, andgolangci-lint run ./...,go vet ./...andgofmtare clean.Notes for reviewers
NVIDIA_CTK_LIBCUDA_DIRbecomes/usr/lib/x86_64-linux-gnu:/usr/lib/i386-linux-gnuon multilib hosts. The variable already carries a list, and the native directory stays first, but any consumer taking the last entry would now get the 32-bit one.NewLibraryLocatorwidens every lookup that uses it, not only 32-bit ones: the ldcache is now consulted even when a predefined search path already matched. Deduplication and native-first ordering keep version inference, which uses the first result, unchanged.--disable-compat32restores the previous first-match behaviour along with the rest.nvidia-cdi-hookwould not be gated. The two ship in the same package.nvidia-ctkwith--library-search-path— take the early return inNewLibraryLocatorand are unaffected by the discovery change. Exposing the 32-bit stack there means passing a second search path for the driver'slib32output; the hook change classifies those directories correctly, since it does not rely on path naming..pathfile only applies to directories that are not searched already, so a driver directory that is also a system directory keeps its position.